﻿using GoPlay.Models;
using GoPlay.Controllers;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.SessionState;
//using GoPlay.Tests.Models;

namespace GoPlay.Tests.Controllers
{
    [TestClass]
    public class ContactsControllerTests
    {
        [TestMethod]
        public void Contact_Index_GET_AsksForIndexView()
        {
            // Arrange
            var controller = GetContactsController(new InMemoryRepository<Contact>());

            // Act
            ViewResult result = controller.Index() as ViewResult;

            // Assert
            Assert.AreNotEqual(null, result);
        }

        [TestMethod]
        public void Contact_Index_GET_RetrievesAllContactsFromRepositoryForThisUser()
        {
            // Arrange
            Contact t = new Contact { Name = "test", UserId = 1 };
            InMemoryRepository<Contact> repository = new InMemoryRepository<Contact>();
            repository.Insert(t);
            t = new Contact { Name = "test2", UserId = 2 };
            repository.Insert(t);
            var controller = GetContactsController(repository);

            // Act
            ViewResult result = controller.Index() as ViewResult;

            // Assert
            var model = (IEnumerable<Contact>)result.Model;
            //CollectionAssert.Contains(model.ToList(), t);
            Assert.AreEqual(model.Count(), 1);
            Assert.AreEqual("test", model.First().Name);
        }

        [TestMethod]
        public void Contact_Create_POST_PutsValidContactIntoRepository()
        {
            // Arrange
            InMemoryRepository<Contact> repository = new InMemoryRepository<Contact>();
            ContactsController controller = GetContactsController(repository);
            Contact Contact = new Contact { Name = "test", UserId = 1 };

            // Act
            controller.Create(Contact);

            // Assert
            IEnumerable<Contact> Contacts = repository.GetAllByUserId(1);
            Assert.IsTrue(Contacts.Contains(Contact));
        }

        [TestMethod]
        public void Contact_Create_POST_ReturnsRedirectOnSuccess()
        {
            // Arrange
            ContactsController controller = GetContactsController(new InMemoryRepository<Contact>());
            Contact Contact = new Contact { Name = "test", UserId = 1 };

            // Act
            var result = (RedirectToRouteResult)controller.Create(Contact);

            // Assert
            Assert.AreEqual("Index", result.RouteValues["action"]);
        }

        [TestMethod]
        public void Contact_Create_POST_ReturnsViewIfModelStateIsNotValid()
        {
            // Arrange
            ContactsController controller = GetContactsController(new InMemoryRepository<Contact>());
            // Simply executing a method during a unit test does just that - executes a method, and no more. 
            // The MVC pipeline doesn't run, so binding and validation don't run.
            controller.ModelState.AddModelError("", "mock error message");
            Contact Contact = new Contact { Name = "test", UserId = 1 };

            // Act
            var result = (ViewResult)controller.Create(Contact);

            // Assert
            Assert.AreEqual("GoPlay.Models.Contact", result.ViewData.Model.ToString());
        }

        [TestMethod]
        public void Contact_Create_POST_ReturnsViewIfRepositoryThrowsException()
        {
            // Arrange
            InMemoryRepository<Contact> repository = new InMemoryRepository<Contact>();
            Exception exception = new Exception();
            repository.ExceptionToThrow = exception;
            ContactsController controller = GetContactsController(repository);
            Contact Contact = new Contact { Name = "test", UserId = 1 };

            // Act
            var result = controller.Create(Contact) as ViewResult;

            // Assert
            ModelState modelState = result.ViewData.ModelState[""];
            Assert.IsNotNull(modelState);
            Assert.IsTrue(modelState.Errors.Any());
            Assert.AreEqual(exception, modelState.Errors[0].Exception);
        }

        [TestMethod]
        public void Contact_Edit_POST_UpdatesContactInRepository()
        {
            //// Arrange
            //InMemoryRepository<Contact> repository = new InMemoryRepository<Contact>();
            //ContactsController controller = GetContactsController(repository);
            //Contact Contact = new Contact { Name = "test", UserId = 1 };

            //// Act
            //controller.Create(Contact);

            //// Assert
            //IEnumerable<Contact> Contacts = repository.GetAllContactsForUser(1);
            //Assert.IsTrue(Contacts.Contains(Contact));
            Assert.Inconclusive();
        }

        [TestMethod]
        public void Contact_Edit_POST_ReturnsRedirectOnSuccess()
        {
            //// Arrange
            //ContactsController controller = GetContactsController(new InMemoryRepository<Contact>());
            //Contact Contact = new Contact { Name = "test", UserId = 1 };

            //// Act
            //var result = (RedirectToRouteResult)controller.Create(Contact);

            //// Assert
            //Assert.AreEqual("Index", result.RouteValues["action"]);
            Assert.Inconclusive();
        }

        [TestMethod]
        public void Contact_Edit_POST_ReturnsViewIfModelStateIsNotValid()
        {
            //// Arrange
            //ContactsController controller = GetContactsController(new InMemoryRepository<Contact>());
            //// Simply executing a method during a unit test does just that - executes a method, and no more. 
            //// The MVC pipeline doesn't run, so binding and validation don't run.
            //controller.ModelState.AddModelError("", "mock error message");
            //Contact Contact = new Contact { Name = "test", UserId = 1 };

            //// Act
            //var result = (ViewResult)controller.Create(Contact);

            //// Assert
            //Assert.AreEqual("GoPlay.Models.Contact", result.ViewData.Model.ToString());
            Assert.Inconclusive();
        }

        [TestMethod]
        public void Contact_Edit_POST_ReturnsViewIfRepositoryThrowsException()
        {
            //// Arrange
            //InMemoryRepository<Contact> repository = new InMemoryRepository<Contact>();
            //Exception exception = new Exception();
            //repository.ExceptionToThrow = exception;
            //ContactsController controller = GetContactsController(repository);
            //Contact Contact = new Contact { Name = "test", UserId = 1 };

            //// Act
            //var result = (ViewResult)controller.Create(Contact);

            //// Assert
            //ModelState modelState = result.ViewData.ModelState[""];
            //Assert.IsNotNull(modelState);
            //Assert.IsTrue(modelState.Errors.Any());
            //Assert.AreEqual(exception, modelState.Errors[0].Exception);
            Assert.Inconclusive();
        }



        private static ContactsController GetContactsController(IRepository<Contact> repository)
        {
            ContactsController controller = new ContactsController(repository);

            var sessionItems = new SessionStateItemCollection();
            sessionItems["UserId"] = "1";
            sessionItems["UserName"] = "chipirek";
            controller.ControllerContext = new MvcFakes.FakeControllerContext(controller, sessionItems);
            return controller;
        }

    }
}
